﻿using System;
using System.Collections.Generic;
using System.Text;
using Common.Utilities.Dispatcher;
using Common.Utilities;
using System.Xml;

namespace Workflows.Components.Rules
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable]
    public class CodeRuleInstruction:InstructionBase
    {
        #region props
        private string _RuleName;
        /// <summary></summary>
        public string RuleName
        {
            get
            {
                return this._RuleName;
            }
            set
            {
                this._RuleName = value;
            }
        }

        private string _CategoryName;
        /// <summary></summary>
        public string CategoryName
        {
            get
            {
                return this._CategoryName;
            }
            set
            {
                this._CategoryName = value;
            }
        }

        private string _InputTypeFullName;
        /// <summary></summary>
        public string InputTypeFullName
        {
            get
            {
                return this._InputTypeFullName;
            }
            set
            {
                this._InputTypeFullName = value;
            }
        }

        private string _InputAssemblyName;
        /// <summary></summary>
        public string InputAssemblyName
        {
            get
            {
                return this._InputAssemblyName;
            }
            set
            {
                this._InputAssemblyName = value;
            }
        }

        private string _Code;
        /// <summary></summary>
        public string Code
        {
            get
            {
                return this._Code;
            }
            set
            {
                this._Code = value;
            }
        }

        private RuleDecision _Decision;
        /// <summary></summary>
        public RuleDecision Decision
        {
            get
            {
                return this._Decision;
            }
            set
            {
                this._Decision = value;
            }
        }

        private string _SerializedInputObject;
        /// <summary></summary>
        public string SerializedInputObject
        {
            get
            {
                return this._SerializedInputObject;
            }
            set
            {
                this._SerializedInputObject = value;
            }
        }
        #endregion

        #region ctor
        /// <summary>
        /// 
        /// </summary>
        public CodeRuleInstruction()
            : base(Guid.Empty, Guid.Empty)
        {
            this._RuleName = string.Empty;
            this._CategoryName = "Misc";
            this._InputTypeFullName = typeof(string).FullName;
            this._Code = string.Empty;
            this._Decision = new RuleDecision();
            this._SerializedInputObject = string.Empty;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="componentID"></param>
        /// <param name="jobTicketID"></param>
        /// <param name="ruleName"></param>
        /// <param name="categoryName"></param>
        /// <param name="inputAssemblyFileName"></param>
        /// <param name="inputTypeFullName"></param>
        /// <param name="code"></param>
        /// <param name="decision"></param>
        /// <param name="serializedInput"></param>
        public CodeRuleInstruction(Guid componentID, Guid jobTicketID,
            string ruleName, 
            string categoryName, 
            string inputAssemblyFileName, 
            string inputTypeFullName, 
            string code, 
            RuleDecision decision,
            string serializedInput)
            : base(componentID, jobTicketID)
        {
            this._RuleName = ruleName;
            this._CategoryName = categoryName;
            this._InputAssemblyName = inputAssemblyFileName;
            this._InputTypeFullName = inputTypeFullName;
            this._Code = code;
            this._Decision = decision;
            this._SerializedInputObject = serializedInput;
        }
        #endregion

        public override XmlNode Serialize(ref XmlDocument xDoc, ref XmlNode parentNode)
        {
            XmlNode xNode = XmlDataUtil.AddElement(ref xDoc, parentNode, "Instruction");
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Type", this.GetType().FullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ComponentID", this.OwnerComponentID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "WorkerID", this.OwnerWorkerInstanceID.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SubmitTime", this.SubmitTime.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "StartTime", this.StartTime.ToString());

            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "RuleName", this.RuleName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "CategoryName", this.CategoryName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "AssemblyName", this.InputAssemblyName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "InputTypeName", this.InputTypeFullName);
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ContinueIfTrue", this.Decision.ContinueIfTrue.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "ContinueIfFalse", this.Decision.ContinueIfFalse.ToString());
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "Code", Base64Util.EncodeAsBase64(this.Code, false));
            XmlDataUtil.UpdateAttribute(ref xDoc, xNode, "SerializedInputObject", this.SerializedInputObject);

            return xNode;
        }

        public override InstructionBase Instantiate(XmlNode xNode)
        {
            if (xNode.Attributes.GetNamedItem("Type").Value == this.GetType().FullName)
            {
                CodeRuleInstruction instruction = new CodeRuleInstruction();
                instruction.OwnerComponentID = new Guid(xNode.Attributes.GetNamedItem("ComponentID").Value);
                instruction.OwnerWorkerInstanceID = new Guid(xNode.Attributes.GetNamedItem("WorkerID").Value);
                instruction.SubmitTime = DateTime.Parse(xNode.Attributes.GetNamedItem("SubmitTime").Value);
                instruction.StartTime = DateTime.Parse(xNode.Attributes.GetNamedItem("StartTime").Value);

                instruction.RuleName = XmlDataUtil.GetAttributeValue(xNode, "RuleName", "");
                instruction.CategoryName = XmlDataUtil.GetAttributeValue(xNode, "CategoryName", "Misc");
                instruction.InputAssemblyName = XmlDataUtil.GetAttributeValue(xNode, "AssemblyName", "");
                instruction.InputTypeFullName = XmlDataUtil.GetAttributeValue(xNode, "InputTypeName", typeof(string).FullName);
                RuleDecision decision = new RuleDecision();
                decision.ContinueIfTrue = bool.Parse(XmlDataUtil.GetAttributeValue(xNode, "ContinueIfTrue", false.ToString()));
                decision.ContinueIfFalse = bool.Parse(XmlDataUtil.GetAttributeValue(xNode, "ContinueIfFalse", false.ToString()));
                instruction.Decision = decision;
                instruction.Code = Base64Util.DecodeAsString(XmlDataUtil.GetAttributeValue(xNode, "Code", ""), false);
                instruction.SerializedInputObject = XmlDataUtil.GetAttributeValue(xNode, "SerializedInputObject", "");

                return instruction;
            }
            else
            {
                throw new Exception("Unable to instantiate instruction: invalid type specified in xml node");
            }
        }
    }
}
